package com.guqj.thread.concurrent.lock;

import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * <p>
 * 	通过一个ReadWriteLock产生两个锁，一个读锁，一个写锁。读操作使用读锁，写操作使用写锁。<br>
 * 	只有"读-读"操作是可以并行的，"读-写"和"写-写"都不可以,只有一个线程可以进行写操作。<br>
 *  在获取写锁时，只有没有任何线程持有任何锁才可以获取到，在持有写锁时，<br>
 *  其他任何线程都获取不到任何锁。在没有其他线程持有写锁的情况下，多个线程可以获取和持有读锁。<br><br>
 *  ReentrantReadWriteLock是可重入的读写锁
 * </p>
 */
public class ReadWriteLockTest {

	public static void main(String[] args) {
		MyAccount account = new MyAccount(UUID.randomUUID().toString(), 10000);
		ExecutorService executor = Executors.newFixedThreadPool(2);
		ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

		User user1 = new User(lock, "茶叶老大", account, 2000);
		User user2 = new User(lock, "金币小藏", account, -212);
		User user3 = new User(lock, "我是第二个", account, 1111);
		User user4 = new User(lock, "陈佩", account, -1000);
		User user5 = new User(lock, "水若兰", account, 0);

		executor.execute(user1);
		executor.execute(user2);
		executor.execute(user3);
		executor.execute(user4);
		executor.execute(user5);

		executor.shutdown();
	}
}

class User implements Runnable {
	private ReentrantReadWriteLock lock = null;
	private String name;
	private MyAccount myAccount;
	private int oscash;

	public User(ReentrantReadWriteLock lock, String name, MyAccount myAccount, int oscash) {
		this.lock = lock;
		this.name = name;
		this.myAccount = myAccount;
		this.oscash = oscash;
	}

	@Override
	public void run() {
		if (oscash == 0) {
			lock.readLock().lock();
			System.out.println("读：" + name + "正在查询" + myAccount + "账户，当前金额为" + myAccount.getAmount());
			lock.readLock().unlock();
		} else {
			lock.writeLock().lock();
			System.out.println("写：" + name + "正在操作" + myAccount + "账户，金额为" + oscash + "，当前金额为" + myAccount.getAmount());
			myAccount.setAmount(myAccount.getAmount() + oscash);
			System.out.println("写：" + name + "操作" + myAccount + "账户成功，金额为" + oscash + "，当前金额为" + myAccount.getAmount());
			lock.writeLock().unlock();
		}
	}

}

class MyAccount {

	private String oid;
	private int amount;

	public MyAccount(String oid, int amount) {
		this.oid = oid;
		this.amount = amount;
	}

	public String getOid() {
		return oid;
	}

	public void setOid(String oid) {
		this.oid = oid;
	}

	public int getAmount() {
		return amount;
	}

	public void setAmount(int amount) {
		this.amount = amount;
	}

	@Override
	public String toString() {
		return "[oid=" + this.oid + ", amount=" + this.amount + "]";
	}

}